﻿using System;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Zadanie5
{
    public delegate void ChangedEventHandler();

    class ReadersWriters
    {
        public event ChangedEventHandler Changed;

        private int readcount = 0;
        private int writecount = 0;
        private Semaphore rsem, wsem;
        private Semaphore x, y, z;

        private Thread[] writers, readers;
        private int N_READERS = 15;
        private int N_WRITERS = 2;

        public int Readcount
        {
            get
            {
                return readcount;
            }
            set
            {
                readcount = value;
                if (Changed != null) Changed();
            }
        }

        private int writersActive;
        public int WritersActive
        {
            get
            {
                return writersActive;
            }
            set
            {
                writersActive = value;
                if (Changed != null) Changed();
            }
        }
        public int WriteCount
        {
            get
            {
                return writecount;
            }
            set
            {
                writecount = value;
                if (Changed != null) Changed();
            }
        }

        private void Writer()
        {
            while (true)
            {
                y.WaitOne();
                WriteCount++;
                if (WriteCount == 1)
                    rsem.WaitOne();
                y.Release();
                wsem.WaitOne();

                WritersActive++;
                // pisanie
                Random rng = new Random();
                Thread.Sleep(500 + rng.Next(1500));
                // koniec pisania
                WritersActive--;

                wsem.Release();
                y.WaitOne();
                WriteCount--;
                if (WriteCount == 0)
                    rsem.Release();
                y.Release();

                Thread.Sleep(2500 + rng.Next(1500));
            }
        }

        private void Reader()
        {
            while (true)
            {
                z.WaitOne();
                rsem.WaitOne();
                x.WaitOne();
                Readcount++;
                if (Readcount == 1)
                    wsem.WaitOne();
                x.Release();
                rsem.Release();
                z.Release();

                // czytanie
                Random rng = new Random();
                Thread.Sleep(500 + rng.Next(1500));
                // koniec czytania

                x.WaitOne();
                Readcount--;
                if (Readcount == 0)
                    wsem.Release();
                x.Release();

                Thread.Sleep(200 + rng.Next(1000));
            }
        }

        public void Run()
        {
            rsem = new Semaphore(1,1);
            wsem = new Semaphore(1,1);
            x = new Semaphore(1,1);
            y = new Semaphore(1,1);
            z = new Semaphore(1, 1);

            readers = new Thread[N_READERS];
            writers = new Thread[N_WRITERS];

            for (int i = 0; i < N_READERS; i++)
            {
                readers[i] = new Thread(Reader);
                readers[i].Start();
            }

            for (int i = 0; i < N_WRITERS; i++)
            {
                writers[i] = new Thread(Writer);
                writers[i].Start();
            }
        }

        public void Stop()
        {
            for (int i = 0; i < N_READERS; i++)
            {
                readers[i].Abort();
            }

            for (int i = 0; i < N_WRITERS; i++)
            {
                writers[i].Abort();
            }
        }
    }
}
